/****************************************************************
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.     *
 *                                                              *
 * Copyright (C) 2009, Jun Li All rights reserved.              *
 * More about Jun{                                              *
 * Homepage: http://www.jpxx.org/                               *
 * Email   : lijun@jpxx.org                                     *
 * }                                                            *
 * SOFTWARE ENGINEERING COLLEGE OF SICHUAN UNIVERSITY           *
 *                                                              *
 ****************************************************************/
package org.jpxx.sec.web.home.servlet;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GraphicsEnvironment;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.LinkedList;
import java.util.Random;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriter;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import javax.imageio.stream.ImageOutputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.jpxx.sec.common.util.Constants;

/**
 * 用于产生验证码。
 * 
 * @author Jun Li lijun@jpxx.org (http://www.jpxx.org)
 * @version 1.0.0 $ org.jpxx.sec.web.home.servlet.VerifyCode.java $ $ Date:
 *          2009-5-16 $
 */
public class VerifyCode extends HttpServlet {

	/**
	 * serialVersion UID
	 */
	private static final long serialVersionUID = -8415153229210464906L;
	private static int number;
	private static long seed;
	private static int IMAGE_WIDTH;
	private static final int IMAGE_HEIGHT = 20;
	private static final String SVG_SOURCE2 = "</text></svg>";
	private boolean svgMode = false;

	/**
	 * Processes requests for both HTTP <code>GET</code> and <code>POST</code>
	 * methods.
	 * 
	 * @param request
	 *            servlet request
	 * @param response
	 *            servlet response
	 */
	protected void processRequest(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {

		String strNumber = null;
		String strSeed = null;
		try {
			strNumber = request.getParameter("Number");
		} catch (Exception e) {
		}

		try {
			strSeed = request.getParameter("Seed");
		} catch (Exception e) {
		}

		if (strNumber == null) {
			number = 6;
			IMAGE_WIDTH = 96;
		} else {
			number = Integer.parseInt(strNumber);
			IMAGE_WIDTH = number * 16;
		}

		if (strSeed == null) {
			seed = System.currentTimeMillis();
		} else {
			seed = Long.parseLong(strSeed);
		}

		String vcode;
		try {
			vcode = sn2vcode();
			request.getSession().setAttribute(
					Constants.JPXX_ADMIN_LOGIN_CODE_SESSION,
					vcode.toLowerCase());
			if (svgMode) {
				outSVG(vcode, response);
			} else {
				outJPEG(vcode, response);
			}
		} catch (InterruptedException ex) {
			ex.printStackTrace();
		}
	}

	private void outSVG(String vcode, HttpServletResponse resp)
			throws IOException {
		resp.setContentType("image/svg+xml");
		String SVG_SOURCE1 = "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">"
				+ "<svg width=\""
				+ IMAGE_WIDTH
				+ "\" height=\""
				+ IMAGE_HEIGHT
				+ "\" xmlns=\"http://www.w3.org/2000/svg\">"
				+ "<text x=\"0\" y=\""
				+ IMAGE_HEIGHT
				+ "\" font-family=\"Arial\" font-size=\""
				+ IMAGE_HEIGHT
				+ "\" fill=\"black\">";
		resp.getOutputStream().print(SVG_SOURCE1 + vcode + SVG_SOURCE2);
	}

	private void outJPEG(String vcode, HttpServletResponse resp)
			throws IOException {
		resp.setContentType("image/jpeg");
		BufferedImage image = new BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT,
				BufferedImage.TYPE_INT_RGB);
		Random random = new Random(seed);
		Graphics g = image.getGraphics();

		g.setColor(getRandColor(100, 250));
		g.fillRect(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
		g.setFont(new Font("Comic Sans MS", Font.CENTER_BASELINE, 18));
		g.setColor(getRandColor(160, 200));

		for (int i = 0; i < 155; i++) {
			int x = random.nextInt(IMAGE_WIDTH);
			int y = random.nextInt(IMAGE_HEIGHT);
			int xl = random.nextInt(12);
			int yl = random.nextInt(12);
			g.drawLine(x, y, x + xl, y + yl);
		}
		for (int i = 1; i <= number; i++) {
			String rand = vcode.substring(i - 1, i).toUpperCase();
			g.setColor(new Color(20 + random.nextInt(110), 20 + random
					.nextInt(110), 20 + random.nextInt(110)));
			g.drawString(rand, 13 * (i - 1) + 0, 16);
		}

		ImageWriter writer = (ImageWriter) ImageIO.getImageWritersByFormatName(
				"jpeg").next();
		JPEGImageWriteParam params = new JPEGImageWriteParam(null);
		ImageOutputStream ios = ImageIO.createImageOutputStream(resp
				.getOutputStream());
		writer.setOutput(ios);
		writer.write(null, new IIOImage(image, null, null), params);
		writer.dispose();
		ios.close();
	}

	static String sn2vcode() throws InterruptedException {
		String sRand = "";
		for (int i = 0; i < number; i++) {
			sRand += getChar();
			Thread.sleep(new Random().nextInt(10) + 10);
		}

		/**
		 * Random random = new Random(); for (int i = 0; i < number; i++) {
		 * String rand = String.valueOf(random.nextInt(10)); sRand += rand; }
		 */
		return sRand;
	}

	@Override
	public void init() throws ServletException {
		try {
			GraphicsEnvironment.getLocalGraphicsEnvironment();
		} catch (Throwable e) {
			svgMode = true;
		}

	}

	public Color getRandColor(int fc, int bc) {
		Random random = new Random();
		if (fc > 255) {
			fc = 255;
		}
		if (bc > 255) {
			bc = 255;
		}
		int r = fc + random.nextInt(bc - fc);
		int g = fc + random.nextInt(bc - fc);
		int b = fc + random.nextInt(bc - fc);
		return new Color(r, g, b);
	}

	public static char getChar() {
		Random random = new Random();
		char ch = '0';
		LinkedList<String> ls = new LinkedList<String>();
		for (int i = 0; i < 10; i++) {// 0-9
			ls.add(String.valueOf(48 + i));
		}

		for (int i = 0; i < 26; i++) {// A-Z
			ls.add(String.valueOf(65 + i));
		}

		for (int i = 0; i < 26; i++) {// a-z
			ls.add(String.valueOf(97 + i));
		}

		int index = random.nextInt(ls.size());
		if (index > (ls.size() - 1)) {
			index = ls.size() - 1;
		}

		ch = (char) Integer.parseInt(String.valueOf(ls.get(index)));
		return ch;
	}

	/**
	 * Handles the HTTP <code>GET</code> method.
	 * 
	 * @param request
	 *            servlet request
	 * @param response
	 *            servlet response
	 */
	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		processRequest(request, response);
	}

	/**
	 * Handles the HTTP <code>POST</code> method.
	 * 
	 * @param request
	 *            servlet request
	 * @param response
	 *            servlet response
	 */
	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		processRequest(request, response);
	}
}
